﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Text;
using System.Globalization;
using Titan.Validation;

namespace Titan.Common
{
    public class CustomConvert
    {
        /// <summary>
        /// 将对象转换为INT类型（出现异常时返回0）
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int TryToInt(object obj)
        {
            try
            {
                return System.Convert.ToInt32(obj);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 将对象转换为Double类型（出现异常时返回0）
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static double TryToDouble(object obj)
        {
            try
            {
                return System.Convert.ToDouble(obj);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 将对象转换为DateTime类型（出现异常时返回最小时间）
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static DateTime TryToDateTime(object obj)
        {
            try
            {
                return System.Convert.ToDateTime(obj.ToString());
            }
            catch
            {
                return System.Convert.ToDateTime(obj.ToString(), new CultureInfo("fr-FR"));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="inputValue"></param>
        /// <param name="outputValue"></param>
        /// <returns></returns>
        public static bool TryConvert<T>(object inputValue, out T outputValue)
        {
            return TryConvert(inputValue, CultureInfo.CurrentCulture, out outputValue);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="inputValue"></param>
        /// <param name="culture"></param>
        /// <param name="outputValue"></param>
        /// <returns></returns>
        public static bool TryConvert<T>(object inputValue, CultureInfo culture, out T outputValue)
        {
            return TryAction<T>(delegate
            {
                object tempConvertedValue;
                TryConvert(inputValue, CultureInfo.CurrentCulture, typeof(T), out tempConvertedValue);

                return (T)tempConvertedValue;
            }, out outputValue);
        }

        public delegate T Creator<T>();

        private static bool TryAction<T>(Creator<T> creator, out T output)
        {
            ValidationUtils.ArgumentNotNull(creator, "creator");

            try
            {
                output = creator();
                return true;
            }
            catch
            {
                output = default(T);
                return false;
            }
        }

        private static bool TryConvert(object inputValue, CultureInfo culture, Type targetType, out object outputValue)
        {
            return TryAction<object>(delegate { return Convert(inputValue, culture, targetType); }, out outputValue);
        }

        private static object Convert(object inputValue, CultureInfo culture, Type targetType)
        {
            if (inputValue == null)
                throw new ArgumentNullException("inputValue");

            Type inputType = inputValue.GetType();

            if (targetType == inputType)
                return inputValue;

            if (targetType.IsInterface || targetType.IsGenericTypeDefinition || targetType.IsAbstract)
                throw new ArgumentException(string.Format("Target type {0} is not a value type or a non-abstract class.", targetType), "targetType");


            // use Convert.ChangeType if both types are IConvertible
            if (inputValue is IConvertible && typeof(IConvertible).IsAssignableFrom(targetType))
            {
                if (inputValue is string && targetType.IsEnum)
                    return Enum.Parse(targetType, inputValue.ToString(), true);
                else
                    return System.Convert.ChangeType(inputValue, targetType, culture);
            }



            TypeConverter toConverter = TypeDescriptor.GetConverter(inputType);

            if (toConverter != null && toConverter.CanConvertTo(targetType))
                return toConverter.ConvertTo(null, culture, inputValue, targetType);

            TypeConverter fromConverter = TypeDescriptor.GetConverter(targetType);

            if (fromConverter != null && fromConverter.CanConvertFrom(inputType))
                return fromConverter.ConvertFrom(null, culture, inputValue);

            throw new Exception(string.Format("Can not convert from {0} to {1}.", inputType, targetType));
        }
    }
}
